package com.acip.uuid.config;

import com.acip.uuid.segment.BusinessCosIdSegmentCache;
import com.acip.uuid.util.ClassScaner;
import com.acip.uuid.util.TableNameConvertUtil;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;

import java.util.Objects;
import java.util.Set;

/**
 * @ClassName IdGeneratorAutoConfig
 * @Description
 * @Author RayLiang
 * @Date 2022/11/28 15:39
 * @Version 1.0
 **/
@Configuration(
        proxyBeanMethods = false
)
@ComponentScan(basePackages = "com.acip.uuid.**")
@MapperScan({
        "com.acip.uuid.mapper.**"
})
@EnableConfigurationProperties(MybatisPlusProperties.class)
@Order(Ordered.HIGHEST_PRECEDENCE+5)
@Slf4j
public class IdGeneratorAutoConfig implements ApplicationContextAware {

    private final MybatisPlusProperties properties;

    private final BusinessCosIdSegmentCache businessCosIdSegmentCache;

    private ApplicationContext applicationContext;

    /**
     * 项目IdWorker使用自定号段链生成分布式id
     */
    private static boolean idWorkerStrategyUseCustom;

    private static String applicationName;

    @Value("${segment.id.strategy.useCustom:true}")
    public void setIdWorkerStrategyChange(boolean idWorkerStrategyUseCustom) {
        this.idWorkerStrategyUseCustom = idWorkerStrategyUseCustom;
    }

    @Value("${spring.application.name:}")
    public void setApplicationName(String applicationName) {
        this.applicationName = applicationName;
    }



    public IdGeneratorAutoConfig(MybatisPlusProperties properties, BusinessCosIdSegmentCache businessCosIdSegmentCache) {
        this.properties = properties;
        this.businessCosIdSegmentCache = businessCosIdSegmentCache;
    }


    @PostConstruct
    public void initSegmentCache(){
        businessCosIdSegmentCache.initCosidSegmentCache();
        if(Objects.nonNull(properties.getTypeAliasesPackage())){
            String[] packageSplit = properties.getTypeAliasesPackage().split("[,;]");
            if(packageSplit !=null && packageSplit.length > 0){
                Set<Class> scan = ClassScaner.scan(packageSplit, null);
                scan.forEach(classs->{
                    TableName tableNameAnnotation = (TableName) classs.getAnnotation(TableName.class);
                    if(Objects.nonNull(tableNameAnnotation)){
                        String tableName = tableNameAnnotation.value();
                        if(StringUtils.isEmpty(tableName)){
                            String camelName = TableNameConvertUtil.toSymbolCase(classs.getSimpleName());
                            this.businessCosIdSegmentCache.getBusinessCosIdGenerator(camelName);
                        }else{
                            this.businessCosIdSegmentCache.getBusinessCosIdGenerator(tableName);
                        }
                    }else{
                        String classsSimpleName = classs.getSimpleName();
                        this.businessCosIdSegmentCache.getBusinessCosIdGenerator(TableNameConvertUtil.toSymbolCase(classsSimpleName));
                    }
                });
            }
        }
        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = this.applicationContext.getBean(MybatisSqlSessionFactoryBean.class);
        if(Objects.nonNull(mybatisSqlSessionFactoryBean)){
            MybatisConfiguration configuration = mybatisSqlSessionFactoryBean.getConfiguration();
            GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(configuration);
            CustomIdGenerator customIdGenerator = new CustomIdGenerator(this.businessCosIdSegmentCache,this.applicationName);
            globalConfig.setIdentifierGenerator(customIdGenerator);
            GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
            dbConfig.setIdType(IdType.ASSIGN_ID);
            if(idWorkerStrategyUseCustom){
                IdWorker.setIdentifierGenerator(customIdGenerator);
            }
        }
        log.info("init Segment Cache Completed ");
    }

    @PreDestroy
    public void saveSegmentCache(){
        businessCosIdSegmentCache.saveCosidSegmentCache();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
